library(tidyverse)
library(rtweet)

Search tweets

search_tweets() - search a keyword(s) or hashtag

I recommend limiting the number of tweets returned (n = 1000) for this training. Otherwise you’ll probably hit a rate limit.

bts <- search_tweets("#BTS", n = 5000, include_rts = FALSE)

Downloading [=>---------------------------------------]   4%
Downloading [=>---------------------------------------]   6%
Downloading [==>--------------------------------------]   8%
Downloading [===>-------------------------------------]  10%
Downloading [====>------------------------------------]  12%
Downloading [=====>-----------------------------------]  14%
Downloading [======>----------------------------------]  16%
Downloading [======>----------------------------------]  18%
Downloading [=======>---------------------------------]  20%
Downloading [========>--------------------------------]  22%
Downloading [=========>-------------------------------]  24%
Downloading [==========>------------------------------]  26%
Downloading [==========>------------------------------]  28%
Downloading [===========>-----------------------------]  30%
Downloading [============>----------------------------]  32%
Downloading [=============>---------------------------]  34%
Downloading [==============>--------------------------]  36%
Downloading [===============>-------------------------]  38%
Downloading [===============>-------------------------]  40%
Downloading [================>------------------------]  42%
Downloading [=================>-----------------------]  44%
Downloading [==================>----------------------]  46%
Downloading [===================>---------------------]  48%
Downloading [===================>---------------------]  50%
Downloading [====================>--------------------]  52%
Downloading [=====================>-------------------]  54%
Downloading [======================>------------------]  56%
Downloading [=======================>-----------------]  58%
Downloading [========================>----------------]  60%
Downloading [========================>----------------]  62%
Downloading [=========================>---------------]  64%
Downloading [==========================>--------------]  66%
Downloading [===========================>-------------]  68%
Downloading [============================>------------]  70%
Downloading [=============================>-----------]  72%
Downloading [=============================>-----------]  74%
Downloading [==============================>----------]  76%
Downloading [===============================>---------]  78%
Downloading [================================>--------]  80%
Downloading [=================================>-------]  82%
Downloading [=================================>-------]  84%
Downloading [==================================>------]  86%
Downloading [===================================>-----]  88%
Downloading [====================================>----]  90%
Downloading [=====================================>---]  92%
Downloading [======================================>--]  94%
Downloading [======================================>--]  96%
Downloading [=======================================>-]  98%
Downloading [=========================================] 100%
bts_dynamite <- search_tweets("#BTS dynamite", n = 5000, include_rts = FALSE)

Downloading [=>---------------------------------------]   4%
Downloading [=>---------------------------------------]   6%
Downloading [==>--------------------------------------]   8%
Downloading [===>-------------------------------------]  10%
Downloading [====>------------------------------------]  12%
Downloading [=====>-----------------------------------]  14%
Downloading [======>----------------------------------]  16%
Downloading [======>----------------------------------]  18%
Downloading [=======>---------------------------------]  20%
Downloading [========>--------------------------------]  22%
Downloading [=========>-------------------------------]  24%
Downloading [==========>------------------------------]  26%
Downloading [==========>------------------------------]  28%
Downloading [===========>-----------------------------]  30%
Downloading [============>----------------------------]  32%
Downloading [=============>---------------------------]  34%
Downloading [==============>--------------------------]  36%
Downloading [===============>-------------------------]  38%
Downloading [===============>-------------------------]  40%
Downloading [================>------------------------]  42%
Downloading [=================>-----------------------]  44%
Downloading [==================>----------------------]  46%
Downloading [===================>---------------------]  48%
Downloading [===================>---------------------]  50%
Downloading [====================>--------------------]  52%
Downloading [=====================>-------------------]  54%
Downloading [======================>------------------]  56%
Downloading [=======================>-----------------]  58%
Downloading [========================>----------------]  60%
Downloading [========================>----------------]  62%
Downloading [=========================>---------------]  64%
Downloading [==========================>--------------]  66%
Downloading [===========================>-------------]  68%
Downloading [============================>------------]  70%
Downloading [=============================>-----------]  72%
Downloading [=============================>-----------]  74%
Downloading [==============================>----------]  76%
Downloading [===============================>---------]  78%
Downloading [================================>--------]  80%
Downloading [=================================>-------]  82%
Downloading [=================================>-------]  84%
Downloading [==================================>------]  86%
Downloading [===================================>-----]  88%
Downloading [====================================>----]  90%
Downloading [=====================================>---]  92%
Downloading [======================================>--]  94%
Downloading [======================================>--]  96%
Downloading [=======================================>-]  98%
Downloading [=========================================] 100%
bts
bts_dynamite

get friends

Find all the accounts a user follows

john_little <-  get_friends("john_little")
john_little

Use the retreived user_id to get more information about those accounts.

john_little_data <- lookup_users(john_little$user_id)
john_little_data

get followers

Who is following me? get_followers()

jrl_flw <- get_followers("john_little")
jrl_flw_data <- lookup_users(jrl_flw$user_id)
jrl_flw_data 

timelines

Get the most recent tweets from an account

rg_tmls <- get_timelines("RhiannonGiddens", n = 3200)
min(created_at) max(created_at)
2015-04-21 13:59:55 2020-10-27 20:49:18
rg_tmls %>% 
  dplyr::filter(created_at > "2016-01-01") %>%  
  dplyr::group_by(screen_name) %>%
  ts_plot("weeks", trim = 1L) +
  ggplot2::geom_point() +
  geom_smooth(se = FALSE, color = "cadetblue") +
  colorblindr::scale_color_OkabeIto() +
  hrbrthemes::theme_ipsum(grid = "Y") +
  ggplot2::theme(
    legend.title = ggplot2::element_blank(),
    legend.position = "bottom", 
    plot.title = ggplot2::element_text(face = "bold")
    ) +
    ggplot2::labs(
    x = NULL, y = NULL,
    title = "Frequency of Twitter statuses",
    subtitle = "Twitter status (tweet) counts aggregated by week from Jan. 2016",
    caption = "Source: Data collected from Twitter's REST API via rtweet"
  )

NA
NA

get_favorites

Get the most recent favorites from a user

rg_faves <- get_favorites("RhiannonGiddens", n = 3000)
rg_faves

Profiles

Search a users’ profiles

gullah <- search_users("#gullah", n = 1000)
Searching for users...
Finished collecting users!
gullah

Location information

Using some additional R libraries, the location information can be geocoded and then visualize.

First, geocode

Use the tidygeocoder package.

# glimpse(rg_tmls)
rg_places <- rg_tmls %>% 
  drop_na(place_name) %>% 
  select(place_name:bbox_coords) %>% 
  distinct() %>% 
  mutate(addr = glue::glue("{place_full_name}, {country}")) %>% 
  tidygeocoder::geocode(addr, method = "osm")

rg_places

Visuzlize

You can create maps in R. Below is one of the easiest, especially if you know ggplot2

rg_places %>% 
  distinct() %>% 
  drop_na(lat) %>% 
  ggplot(aes(long, lat), color="grey99") +
  borders("world") + 
  geom_point(color = "goldenrod") + 
  ggrepel::geom_label_repel(aes(label = place_full_name), 
                            segment.color = "goldenrod", segment.size = 1,
                            color = "navy") + 
  theme_void()

Second location example

Very similar to above. For accounts with “#gullah” in their profile, and that have location information listed, then geocode the location …..

gullah_places <- gullah %>% 
  drop_na(place_name) %>% 
  select(place_name:bbox_coords) %>% 
  filter(country_code == "US")  %>%
  distinct(place_name, place_full_name, country) %>% 
  mutate(addr = glue::glue("{place_full_name}, {country}")) %>% 
  tidygeocoder::geocode(addr, method = "osm")

gullah_places

And visualize on a US map of the lower 48 states.

You can learn more about basic R mapping from our workshop on mapping with R

gullah_places %>% 
  distinct() %>% 
  drop_na(lat) %>% 
  ggplot(aes(long, lat), color="grey99") +
  borders("state") + 
  geom_point(color = "goldenrod") + 
  ggrepel::geom_label_repel(aes(label = place_full_name), 
                            segment.color = "goldenrod", segment.size = 1,
                            color = "navy") + 
  theme_void()

LS0tDQp0aXRsZTogImdhdGhlciB3aXRoIHJ0d2VldCINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCg0KYGBge3J9DQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkocnR3ZWV0KQ0KYGBgDQoNCi0gaHR0cHM6Ly9kb2NzLnJvcGVuc2NpLm9yZy9ydHdlZXQvDQotIFtJbnRyb2R1Y3Rpb24gdG8gZ2F0aGVyaW5nIHR3ZWV0cyB3aXRoIHJ3dGVldF0oaHR0cHM6Ly9kb2NzLnJvcGVuc2NpLm9yZy9ydHdlZXQvYXJ0aWNsZXMvaW50cm8uaHRtbCkNCg0KDQojIyBTZWFyY2ggdHdlZXRzDQoNCmBzZWFyY2hfdHdlZXRzKClgIC0gc2VhcmNoIGEga2V5d29yZChzKSBvciBoYXNodGFnDQoNCkkgcmVjb21tZW5kIGxpbWl0aW5nIHRoZSBudW1iZXIgb2YgdHdlZXRzIHJldHVybmVkIChgbiA9IDEwMDBgKSBmb3IgdGhpcyB0cmFpbmluZy4gIE90aGVyd2lzZSB5b3UnbGwgcHJvYmFibHkgaGl0IGEgcmF0ZSBsaW1pdC4NCg0KYGBge3J9DQpidHMgPC0gc2VhcmNoX3R3ZWV0cygiI0JUUyIsIG4gPSA1MDAwLCBpbmNsdWRlX3J0cyA9IEZBTFNFKQ0KDQpidHNfZHluYW1pdGUgPC0gc2VhcmNoX3R3ZWV0cygiI0JUUyBkeW5hbWl0ZSIsIG4gPSA1MDAwLCBpbmNsdWRlX3J0cyA9IEZBTFNFKQ0KYGBgDQoNCmBgYHtyfQ0KYnRzDQpidHNfZHluYW1pdGUNCmBgYA0KDQojIyBnZXQgZnJpZW5kcw0KDQpGaW5kIGFsbCB0aGUgYWNjb3VudHMgYSB1c2VyIGZvbGxvd3MNCg0KYGBge3J9DQpqb2huX2xpdHRsZSA8LSAgZ2V0X2ZyaWVuZHMoImpvaG5fbGl0dGxlIikNCmBgYA0KDQpgYGB7cn0NCmpvaG5fbGl0dGxlDQpgYGANCg0KVXNlIHRoZSByZXRyZWl2ZWQgYHVzZXJfaWRgIHRvIGdldCBtb3JlIGluZm9ybWF0aW9uIGFib3V0IHRob3NlIGFjY291bnRzLg0KDQpgYGB7cn0NCmpvaG5fbGl0dGxlX2RhdGEgPC0gbG9va3VwX3VzZXJzKGpvaG5fbGl0dGxlJHVzZXJfaWQpDQpgYGANCg0KYGBge3J9DQpqb2huX2xpdHRsZV9kYXRhDQpgYGANCg0KIyMgZ2V0IGZvbGxvd2Vycw0KDQpXaG8gaXMgZm9sbG93aW5nIG1lPyAgYGdldF9mb2xsb3dlcnMoKWANCg0KYGBge3J9DQpqcmxfZmx3IDwtIGdldF9mb2xsb3dlcnMoImpvaG5fbGl0dGxlIikNCmBgYA0KDQoNCmBgYHtyfQ0KanJsX2Zsd19kYXRhIDwtIGxvb2t1cF91c2VycyhqcmxfZmx3JHVzZXJfaWQpDQpgYGANCg0KDQpgYGB7cn0NCmpybF9mbHdfZGF0YSANCmBgYA0KDQojIyB0aW1lbGluZXMNCg0KR2V0IHRoZSBtb3N0IHJlY2VudCB0d2VldHMgZnJvbSBhbiBhY2NvdW50DQoNCmBgYHtyfQ0KcmdfdG1scyA8LSBnZXRfdGltZWxpbmVzKCJSaGlhbm5vbkdpZGRlbnMiLCBuID0gMzIwMCkNCmBgYA0KDQoNCm1pbihjcmVhdGVkX2F0KSAgICAgfCBtYXgoY3JlYXRlZF9hdCkNCi0tLS0tLS0tLS0tLS0tLS0tLS0gfCAtLS0NCjIwMTUtMDQtMjEgMTM6NTk6NTUgfAkyMDIwLTEwLTI3IDIwOjQ5OjE4CQ0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFfQ0KcmdfdG1scyAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoY3JlYXRlZF9hdCA+ICIyMDE2LTAxLTAxIikgJT4lICANCiAgZHBseXI6Omdyb3VwX2J5KHNjcmVlbl9uYW1lKSAlPiUNCiAgdHNfcGxvdCgid2Vla3MiLCB0cmltID0gMUwpICsNCiAgZ2dwbG90Mjo6Z2VvbV9wb2ludCgpICsNCiAgZ2VvbV9zbW9vdGgoc2UgPSBGQUxTRSwgY29sb3IgPSAiY2FkZXRibHVlIikgKw0KICBjb2xvcmJsaW5kcjo6c2NhbGVfY29sb3JfT2thYmVJdG8oKSArDQogIGhyYnJ0aGVtZXM6OnRoZW1lX2lwc3VtKGdyaWQgPSAiWSIpICsNCiAgZ2dwbG90Mjo6dGhlbWUoDQogICAgbGVnZW5kLnRpdGxlID0gZ2dwbG90Mjo6ZWxlbWVudF9ibGFuaygpLA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLCANCiAgICBwbG90LnRpdGxlID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIpDQogICAgKSArDQogICAgZ2dwbG90Mjo6bGFicygNCiAgICB4ID0gTlVMTCwgeSA9IE5VTEwsDQogICAgdGl0bGUgPSAiRnJlcXVlbmN5IG9mIFR3aXR0ZXIgc3RhdHVzZXMiLA0KICAgIHN1YnRpdGxlID0gIlR3aXR0ZXIgc3RhdHVzICh0d2VldCkgY291bnRzIGFnZ3JlZ2F0ZWQgYnkgd2VlayBmcm9tIEphbi4gMjAxNiIsDQogICAgY2FwdGlvbiA9ICJTb3VyY2U6IERhdGEgY29sbGVjdGVkIGZyb20gVHdpdHRlcidzIFJFU1QgQVBJIHZpYSBydHdlZXQiDQogICkNCg0KDQpgYGANCg0KIyMgZ2V0X2Zhdm9yaXRlcw0KDQpHZXQgdGhlIG1vc3QgcmVjZW50IGZhdm9yaXRlcyBmcm9tIGEgdXNlcg0KDQpgYGB7cn0NCnJnX2ZhdmVzIDwtIGdldF9mYXZvcml0ZXMoIlJoaWFubm9uR2lkZGVucyIsIG4gPSAzMDAwKQ0KYGBgDQoNCmBgYHtyfQ0KcmdfZmF2ZXMNCmBgYA0KDQojIyBQcm9maWxlcw0KDQpTZWFyY2ggYSB1c2VycycgcHJvZmlsZXMNCg0KDQpgYGB7cn0NCmd1bGxhaCA8LSBzZWFyY2hfdXNlcnMoIiNndWxsYWgiLCBuID0gMTAwMCkNCmBgYA0KDQoNCmBgYHtyfQ0KZ3VsbGFoDQpgYGANCg0KIyMgZ2V0IHRyZW5kcw0KDQpXaGF0IGlzIHRyZW5kaW5naW4gYSBzcGVjaWZpYyBsb2NhdGlvbj8NCg0KYGBge3J9DQojIHNmIDwtIGdldF90cmVuZHMoInNhbiBmcmFuY2lzbyIpDQojIGR1cmhhbSA8LSBnZXRfdHJlbmRzKGxhdCA9IDM2LjAsIGxuZyA9IC03OC45KQ0KZ3JlZW5zYm9ybyA8LSBnZXRfdHJlbmRzKCJncmVlbnNib3JvIikNCmBgYA0KDQpgYGB7cn0NCmdyZWVuc2Jvcm8NCmBgYA0KDQojIyBMb2NhdGlvbiBpbmZvcm1hdGlvbg0KDQpVc2luZyBzb21lIGFkZGl0aW9uYWwgUiBsaWJyYXJpZXMsIHRoZSBsb2NhdGlvbiBpbmZvcm1hdGlvbiBjYW4gYmUgZ2VvY29kZWQgYW5kIHRoZW4gdmlzdWFsaXplLg0KDQojIyMgRmlyc3QsIGdlb2NvZGUgDQoNClVzZSB0aGUgW3RpZHlnZW9jb2Rlcl0oaHR0cHM6Ly9qZXNzZWNhbWJvbi5naXRodWIuaW8vdGlkeWdlb2NvZGVyKSBwYWNrYWdlLiAgDQoNCmBgYHtyfQ0KIyBnbGltcHNlKHJnX3RtbHMpDQpyZ19wbGFjZXMgPC0gcmdfdG1scyAlPiUgDQogIGRyb3BfbmEocGxhY2VfbmFtZSkgJT4lIA0KICBzZWxlY3QocGxhY2VfbmFtZTpiYm94X2Nvb3JkcykgJT4lIA0KICBkaXN0aW5jdCgpICU+JSANCiAgbXV0YXRlKGFkZHIgPSBnbHVlOjpnbHVlKCJ7cGxhY2VfZnVsbF9uYW1lfSwge2NvdW50cnl9IikpICU+JSANCiAgdGlkeWdlb2NvZGVyOjpnZW9jb2RlKGFkZHIsIG1ldGhvZCA9ICJvc20iKQ0KDQpyZ19wbGFjZXMNCmBgYA0KDQojIyMgVmlzdXpsaXplIA0KDQpZb3UgY2FuIGNyZWF0ZSBtYXBzIGluIFIuICBCZWxvdyBpcyBvbmUgb2YgdGhlIGVhc2llc3QsIGVzcGVjaWFsbHkgaWYgeW91IGtub3cgW2dncGxvdDJdKGh0dHBzOi8vZ2dwbG90Mi50aWR5dmVyc2Uub3JnKQ0KDQpgYGB7cn0NCnJnX3BsYWNlcyAlPiUgDQogIGRpc3RpbmN0KCkgJT4lIA0KICBkcm9wX25hKGxhdCkgJT4lIA0KICBnZ3Bsb3QoYWVzKGxvbmcsIGxhdCksIGNvbG9yPSJncmV5OTkiKSArDQogIGJvcmRlcnMoIndvcmxkIikgKyANCiAgZ2VvbV9wb2ludChjb2xvciA9ICJnb2xkZW5yb2QiKSArIA0KICBnZ3JlcGVsOjpnZW9tX2xhYmVsX3JlcGVsKGFlcyhsYWJlbCA9IHBsYWNlX2Z1bGxfbmFtZSksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlZ21lbnQuY29sb3IgPSAiZ29sZGVucm9kIiwgc2VnbWVudC5zaXplID0gMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJuYXZ5IikgKyANCiAgdGhlbWVfdm9pZCgpDQpgYGANCg0KIyMjIFNlY29uZCBsb2NhdGlvbiBleGFtcGxlDQoNClZlcnkgc2ltaWxhciB0byBhYm92ZS4gIEZvciBhY2NvdW50cyB3aXRoICIjZ3VsbGFoIiBpbiB0aGVpciBwcm9maWxlLCBhbmQgdGhhdCBoYXZlIGxvY2F0aW9uIGluZm9ybWF0aW9uIGxpc3RlZCwgdGhlbiBnZW9jb2RlIHRoZSBsb2NhdGlvbiAuLi4uLg0KDQpgYGB7cn0NCmd1bGxhaF9wbGFjZXMgPC0gZ3VsbGFoICU+JSANCiAgZHJvcF9uYShwbGFjZV9uYW1lKSAlPiUgDQogIHNlbGVjdChwbGFjZV9uYW1lOmJib3hfY29vcmRzKSAlPiUgDQogIGZpbHRlcihjb3VudHJ5X2NvZGUgPT0gIlVTIikgICU+JQ0KICBkaXN0aW5jdChwbGFjZV9uYW1lLCBwbGFjZV9mdWxsX25hbWUsIGNvdW50cnkpICU+JSANCiAgbXV0YXRlKGFkZHIgPSBnbHVlOjpnbHVlKCJ7cGxhY2VfZnVsbF9uYW1lfSwge2NvdW50cnl9IikpICU+JSANCiAgdGlkeWdlb2NvZGVyOjpnZW9jb2RlKGFkZHIsIG1ldGhvZCA9ICJvc20iKQ0KDQpndWxsYWhfcGxhY2VzDQpgYGANCg0KQW5kIHZpc3VhbGl6ZSBvbiBhIFVTIG1hcCBvZiB0aGUgX2xvd2VyIDQ4XyBzdGF0ZXMuDQoNCllvdSBjYW4gbGVhcm4gbW9yZSBhYm91dCBiYXNpYyBSIG1hcHBpbmcgZnJvbSBvdXIgd29ya3Nob3Agb24gW21hcHBpbmcgd2l0aCBSXShodHRwczovL3JmdW4ubGlicmFyeS5kdWtlLmVkdS9wb3J0Zm9saW8vbWFwcGluZ193b3Jrc2hvcC8pDQoNCg0KYGBge3J9DQpndWxsYWhfcGxhY2VzICU+JSANCiAgZGlzdGluY3QoKSAlPiUgDQogIGRyb3BfbmEobGF0KSAlPiUgDQogIGdncGxvdChhZXMobG9uZywgbGF0KSwgY29sb3I9ImdyZXk5OSIpICsNCiAgYm9yZGVycygic3RhdGUiKSArIA0KICBnZW9tX3BvaW50KGNvbG9yID0gImdvbGRlbnJvZCIpICsgDQogIGdncmVwZWw6Omdlb21fbGFiZWxfcmVwZWwoYWVzKGxhYmVsID0gcGxhY2VfZnVsbF9uYW1lKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VnbWVudC5jb2xvciA9ICJnb2xkZW5yb2QiLCBzZWdtZW50LnNpemUgPSAxLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gIm5hdnkiKSArIA0KICB0aGVtZV92b2lkKCkNCmBgYA0KDQoNCg==